package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.ICBC;
import com.file.bo.mail.ICBCTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class ICBCPdfParser extends BaseDecryptPdfParser {

	public ResponseData<String> parseICBCPdfToJson(String filePath, String pdfPassword) {
		log.info("parseICBCPdfToJson started, filePath:{}, pdfPassword:{}", filePath,  pdfPassword);
		String json = null;

		try {
			ICBC icbc = parseICBCPdf(filePath, pdfPassword);
			json = JsonUtils.convertObjectToJson(icbc);
		} catch (Exception e) {
			log.error("[OnError]parseICBCPdfToJson failed, filePath:{}, pdfPassword:{}", filePath,  pdfPassword, e);
			return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(),
					ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
		}

		log.info("parseICBCPdfToJson completed, filePath:{}, pdfPassword:{}", filePath, pdfPassword);
		return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
	}

	private ICBC parseICBCPdf(String filePath, String pdfPassword) {
		ICBC icbc = parseICBCHeader(filePath, pdfPassword);
		List<ICBCTran> icbcTrans = parseICBCTrans(filePath, pdfPassword);
		icbc.setIcbcTrans(icbcTrans);
		log.info("icbc = " + icbc);
		return icbc;
	}

	private ICBC parseICBCHeader(String filePath, String pdfPassword) {
		ICBC icbc = new ICBC();
		String pdfHeaderText = parsePdfHeaderText(filePath, pdfPassword);
		String cardNo = pdfHeaderText.substring(pdfHeaderText.indexOf("卡号") + 2, pdfHeaderText.indexOf("户名：")).trim();
		String name = pdfHeaderText.substring(pdfHeaderText.indexOf("户名：") + 3, pdfHeaderText.indexOf("起止日期：")).trim();
		String transDetailPeriod = pdfHeaderText
				.substring(pdfHeaderText.indexOf("起止日期：") + 5, pdfHeaderText.indexOf("交易日期")).trim();
		icbc.setCardNo(cardNo);
		icbc.setName(name);
		icbc.setTransDetailPeriod(transDetailPeriod);
		return icbc;
	}

	private List<ICBCTran> parseICBCTrans(String filePath, String pdfPassword) {
		List<ICBCTran> icbcTrans = new ArrayList<>();

		// 1. 读取文件
		File pdf = new File(filePath);

		// 2. pdfbox读取PDDocument
		try (PDDocument pdfDocument = PDDocument.load(pdf, pdfPassword)) {
			// 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
			ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
			NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
			Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

			// 4. 获取每页的PageIterator
			PageIterator pages = objectExtractor.extract();

			// 5. 解析每页的Rectangle(table的位置)
			while (pages.hasNext()) {
				Page page = pages.next();
				List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
				if (tablesOnPage.size() > 0) {
					detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
				}
			}

			// 6.通过table位置获取表格具体内容
			SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

			// 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
			for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
				Page page = objectExtractor.extract(entry.getKey());

				// 默认每页只有一个表格，因此获取第0个rectangle
				Rectangle rectangle = entry.getValue().get(0);
				Page area = page.getArea(rectangle.getTop(), rectangle.getLeft(), rectangle.getBottom(),
						rectangle.getRight());

				List<Table> table = bea.extract(area);
				// 默认每页只有一个表格，因此获取第0个table
				Table t = table.get(0);

				// 判断pdf是否改版，当前版本(20210923)工行流水有13列数据
				if (t.getColCount() != 13) {
					log.error("[OnError]ICBC format invalid.");
					throw new RuntimeException("ICBC format invalid");
				}

				// 每一页都需要去掉表格的header
				for (int i = 0; i < t.getRowCount(); i++) {
					if (t.getCell(i, 0).getText(false).contains("交易日期")
							|| t.getCell(i, 0).getText(false).contains("中国工商银行借记账户历史明细(电子版)")
							|| StringUtils.isEmpty(t.getCell(i, 0).getText(false))) {
						continue;
					}
					ICBCTran icbcTran = getTransactionByTable(t, i);
					icbcTrans.add(icbcTran);
				}
			}
		} catch (Exception e) {
			log.error("[OnError]parseTrans failed", e);
			throw new RuntimeException(e);
		}

		return icbcTrans;
	}

	private ICBCTran getTransactionByTable(Table t, int i) {
		ICBCTran icbcTran = new ICBCTran();
		icbcTran.setTranDate(t.getCell(i, 0).getText(false));
		icbcTran.setAccountNo(t.getCell(i, 1).getText(false));
		icbcTran.setAccountType(t.getCell(i, 2).getText(false));
		icbcTran.setSequenceNo(t.getCell(i, 3).getText(false));
		icbcTran.setCurrency(t.getCell(i, 4).getText(false));
		icbcTran.setCashExchange(t.getCell(i, 5).getText(false));
		icbcTran.setComment(t.getCell(i, 6).getText(false));
		icbcTran.setZone(t.getCell(i, 7).getText(false));
		icbcTran.setIncomeExpenseAmt(t.getCell(i, 8).getText(false));
		icbcTran.setBalance(t.getCell(i, 9).getText(false));
		icbcTran.setCounterpartyName(t.getCell(i, 10).getText(false));
		icbcTran.setConterpartyAccountNo(t.getCell(i, 11).getText(false));
		icbcTran.setChannel(t.getCell(i, 12).getText(false));
		return icbcTran;
	}

	public static void main(String[] args) {
		ICBCPdfParser icbcPdfParser = new ICBCPdfParser();
//		ICBC icbc = icbcPdfParser.parseICBCPdf("E:\\data\\files\\ICBC\\工商银行历史明细（申请单号：21101110272797156865）625486.pdf", "625486");
//		String json = JsonUtils.convertObjectToJson(icbc);
		ICBC icbc = icbcPdfParser.parseICBCPdf("E:\\data\\files\\ICBC\\工商银行交易明细（显示对方户名）.pdf", "625486");
		String json = JsonUtils.convertObjectToJson(icbc);
		log.info(json);
	}

}
